const path = require('path')
const jwt = require('jsonwebtoken')
const { JWT_SECRET } = require('../config/config.default')

const { koaBody } = require('koa-body')

const { bcryptjs, bcryptjsDeclassify } = require('../utils/encrypt')
const { checkDirExist } = require('../utils/uploadFileHandler')
const { getUserInfo, getUserList } = require('../service/user.service')
const {
    formateError,
    userAlreadyExisted,
    userTelAlreadyExisted,
    userAddError,
    userDoesNotExist,
    userLoginDoesNotExist,
    userLoginError,
    invalidPassword,
    insufficientPermissionsError,
    userTelRepeatError
} = require('../constant/err.type')

/**
 * 判断是否存在openid
 */
async function isOpenId (ctx, next) {
    const { openid } = ctx.request.body
    if (openid) {
        try {
            const userDataValues = await getUserInfo({ openid })
            if (userDataValues.length === 0) {
                ctx.status = 200
                ctx.body = {
                    hasOk: true,
                    code: 20000,
                    message: '初次登录，是否绑定账号',
                    data: { firstLogin: true, openid: openid }
                }
            } else {
                ctx.status = 200
                ctx.body = {
                    hasOk: true,
                    code: 20000,
                    message: '用户登录成功',
                    data: {
                        id: userDataValues[0].id,
                        // jwt.sign(载荷[加密的内容]，加密的秘钥，过期时间)
                        token: jwt.sign({ userAccount: userDataValues[0].user_account, role: userDataValues[0].role }, JWT_SECRET, { expiresIn: '6h' })
                    }
                }
            }
        } catch (error) {
            console.log(error)
        }
    } else {
        await next()
    }
}


/**
 * 判断用户是否存在
 */
async function userIsExist (ctx, next) {
    try {
        const { userAccount } = ctx.request.body
        console.log(userAccount)
        if (!userAccount) {
            console.error('用户编码为空', ctx.request.body)
            ctx.app.emit('error', formateError, ctx)
            return
        }
        const accountRes = await getUserInfo({ user_account: userAccount })
        if (accountRes.length === 0) {
            console.error('用户不存在', ctx.request.body)
            ctx.app.emit('error', userDoesNotExist, ctx)
            return
        }
        await next()
    } catch (error) {
        console.log(error)
    }
}

/**
 * 判断新建用户(注册)数据完整性
 */
async function userRegisterValidator (ctx, next) {
    const { userAccount, password, userName, role } = ctx.request.body
    if (!userAccount || !password) {
        console.error('账号或密码为空：', ctx.request.body)
        ctx.app.emit('error', formateError, ctx)
        return
    }
    if (!userName || !role) {
        console.error('必要的用户信息不完整', ctx.request.body)
        ctx.app.emit('error', formateError, ctx)
        return
    }
    await next()
}

/**
 * 判断登录用户数据完整性
 */
async function userLoginValidator (ctx, next) {
    const { userAccount, password } = ctx.request.body
    if (!userAccount || !password) {
        console.error('账号或密码为空：', ctx.request.body)
        ctx.app.emit('error', userLoginError, ctx)
        return
    }
    await next()
}

/**
 * 判断修改用书数据的数据完整性
 */
async function userModifyValidator (ctx, next) {
    // user_account、user_name、userTel、role这些字段不能为空
    const { userAccount, userName, userTel, role } = ctx.request.body
    if (!userAccount || !userName || !role || !userTel) {
        console.error('数据不完整', ctx.request.body)
        ctx.app.emit('error', formateError, ctx)
        return
    }
    // 判断修改的用户是否存在
    const res = await getUserInfo({ user_account: userAccount })
    if (res.length === 0) {
        console.error('用户不存在', ctx.request.body)
        ctx.app.emit('error', userDoesNotExist, ctx)
        return
    }
    await next()
}

/**
 * 判断手机号是否唯一
 */
async function userTelValidator (ctx, next) {
    try {
        const { userTel, userAccount } = ctx.request.body
        const res = await getUserList()
        const userTelRepeat = res.rows.some(item => item.user_tel == userTel && item.user_account !== userAccount)
        if (userTelRepeat) {
            console.error('手机号已被注册', ctx.request.body)
            ctx.app.emit('error', userTelRepeatError, ctx)
            return
        }

        await next()
    } catch (error) {
        console.log(error)
    }
}


/**
 * 判断数据唯一性
 */
async function verifyRegister (ctx, next) {
    const { userAccount, userTel } = ctx.request.body
    try {
        const accountRes = await getUserInfo({ user_account: userAccount })
        if (accountRes.length !== 0) {
            console.error('用户已经存在', ctx.request.body)
            ctx.app.emit('error', userAlreadyExisted, ctx)
            return
        }
        const telRes = await getUserInfo({ user_tel: userTel })
        if (telRes.length !== 0) {
            console.error('该电话号码已经被使用', ctx.request.body)
            ctx.app.emit('error', userTelAlreadyExisted, ctx)
            return
        }
    } catch (error) {
        console.error(error)
        ctx.app.emit('error', userAddError, ctx)
        return
    }
    await next()
}

/**
 * 用户登录判断
 */
async function verifyLogin (ctx, next) {
    const { userAccount, password } = ctx.request.body
    try {
        // 1. 判断登录用户是否存在
        const res = await getUserInfo({ user_account: userAccount })
        if (res.length === 0) {
            // 用户不存在
            console.error('用户不存在', ctx.request.body)
            ctx.app.emit('error', userLoginDoesNotExist, ctx)
            return
        }
        // 2. 用户存在，判断密码是否匹配
        const userDataValues = res[0].dataValues
        if (!bcryptjsDeclassify(password, userDataValues.password)) {
            // 密码不匹配
            console.error('密码错误', ctx.request.body)
            ctx.app.emit('error', invalidPassword, ctx)
            return
        }
    } catch (error) {
        console.error(error)
        ctx.app.emit('error', userLoginError, ctx)
        return
    }
    await next()
}

/**
 * 密码加密
 */
async function cryptPassword (ctx, next) {
    const { password } = ctx.request.body
    // 使用bcryptjs加密密码
    const encryptPassword = bcryptjs(password)
    ctx.request.body.password = encryptPassword
    await next()
}

/**
 * 上传头像时koa-body 图片上传配置
 */
const avatarKoaBody = koaBody({
    multipart: true,
    formidable: {
        uploadDir: path.join(__dirname, "../public/upload"),
        keepExtensions: true,
        filter: (part) => {
            // 判断图片的类型
            const fileTpyes = ['image/jpeg', 'image/png', 'image/gif', 'image/jpg']
            if (!fileTpyes.includes(part.mimetype)) {
                // 图片是系统不支持的类型则返回错误注册失败
                console.error('不支持的图片类型')
                return false
            } else {
                return true
            }
        },
        onFileBegin: (name, file) => {
            // 获取上传文件的后缀
            // let ext = file.originalFilename.split('.')
            // 最终要保存到的文件夹目录（暂时使用name作为次级目录）
            let dir = ''
            dir = path.join(__dirname, `../public/upload/${name}`)
            // 检查文件夹是否存在, 如果不存在则新建文件夹
            checkDirExist(dir)
            // 拼接存放地址
            file.filepath = `${dir}/${file.newFilename}`
        },
    },
    onError: (err, ctx) => {
        console.error(err)
    }
})

/**
 * 头像上传之后处理存入地址的格式
 */
async function uploadAvatarFormat (ctx, next) {
    try {
        // 判断是否有符合条件的头像
        const files = ctx.request.files
        if (!files || Object.keys(files).length === 0) {
            console.error('头像上传失败', files)
            ctx.app.emit('error', avatarError, ctx)
            return
        }
        // 更改头像存入数据库的路径
        const newPath = 'avatar/' + path.basename(files.avatar.filepath)
        const avatar = newPath
        ctx.state.avatar = avatar
        await next()
    } catch (error) {
        console.log(error)
    }
}

/**
 * 判断操作用户是否为管理员身份
 */
async function verifyAdminRole (ctx, next) {
    const { role } = ctx.state.token
    if (role !== 'admin' && role !== 'super_admin') {
        console.error('操作用户非管理员身份，权限不足', ctx.request.body)
        ctx.app.emit('error', insufficientPermissionsError, ctx)
        return
    }
    await next()
}


module.exports = {
    userIsExist,
    userRegisterValidator,
    userLoginValidator,
    userModifyValidator,
    verifyRegister,
    verifyLogin,
    cryptPassword,
    uploadAvatarFormat,
    avatarKoaBody,
    verifyAdminRole,
    userTelValidator,
    isOpenId
}